<?php

namespace App\Http\Controllers;

use App\Http\Utils\Currency\AliPay;
use App\Http\Utils\Currency\Order;
use App\Http\Utils\Currency\TtgPay;
use App\Http\Utils\Currency\WeChat;
use App\Http\Utils\Response;
use App\Jobs\PayNotifyJob;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Payment\Config;
use Payment\Notify\PayNotifyInterface;

class PayController extends Controller implements PayNotifyInterface
{

    /**
     * @var array
     */
    protected $payment = [
        'ttg'    => \App\Http\Utils\Currency\TtgPay::class,
        'wechat' => \App\Http\Utils\Currency\WeChat::class,
        'alipay' => \App\Http\Utils\Currency\AliPay::class,
    ];

    /**
     * @param Request $request
     * @param $shopId
     * @return Response
     */
    public function payList(Request $request, $shopId)
    {
        return $this->json(
            (new TtgPay())->payList($shopId)
        );
    }

    /**
     * @param Request $request
     * @return Response
     */
    public function pay(Request $request)
    {
        $this->validate($request, [
            'user_id'  => 'required|alpha_num',
            'shop_id'  => 'required|alpha_num',
            'amount'   => 'required|integer|min:1',
            'order_no' => 'required|string',
            'callback' => 'required|string|max:200',
            'payment'  => 'required|in:wechat,alipay,ttg',
            'other'    => 'required|array',
        ]);
        $userId = $request->input('user_id');
        $shopId = $request->input('shop_id');
        $orderNum = $request->input('order_no');
        $amount = $request->input('amount');
        $payment = $request->input('payment');
        $callback = $request->input('callback');
        $other = $request->input('other');
        $order = new Order($userId, $shopId, $orderNum, $amount, $this->payment[$payment], $callback, $other);
        $payinfo = $order->pay();
        $currentTime = time();
        DB::table('payinfo')->insert([
            'shop_id'     => $shopId,
            'user_id'     => $userId,
            'order_num'   => $orderNum,
            'amount'      => $amount,
            'payment'     => $payment,
            'callback'    => $callback,
            'other'       => json_encode($other),
            'status'      => 'fail',
            'create_time' => $currentTime,
            'update_time' => $currentTime,
        ]);
        return $this->json($payinfo);
    }

    /**
     * @return array
     */
    public function wechatNotify()
    {
        return (new WeChat())->notify($this);
    }

    /**
     * @return array
     */
    public function alipayNotify()
    {
        return (new AliPay())->notify($this);
    }

    /**
     * @return string
     */
    public function ttgNotify()
    {
        return (new TtgPay())->notify($this);
    }

    /**
     * @param array $data
     * @return bool
     * @throws \Exception
     */
    public function notifyProcess(array $data)
    {
        $channel = $data['channel'];
        if ($channel === Config::ALI_CHARGE) {
            Log::info('支付宝支付');
            Log::info(print_r($data, true));
        } elseif ($channel === Config::WX_CHARGE) {
            Log::info('微信支付');
            Log::info(print_r($data, true));
        } elseif ($channel === TtgPay::TTG) {
            Log::info('淘淘谷支付');
            Log::info(print_r($data, true));
        }
        DB::beginTransaction();
        try {
            $order = DB::table('payinfo')->where('order_num', $data['order_no'])->lockForUpdate()->first();
            if (!is_null($order) && $order->status == 'fail') {
                DB::table('payinfo')->where('order_num', $data['order_no'])->update([
                    'status'      => 'success',
                    'update_time' => time(),
                ]);
                $this->dispatch((new PayNotifyJob(
                    $order->callback, [
                    'tradeNo' => $order->order_num,
                    'userId'  => $order->user_id,
                    'shopId'  => $order->shop_id,
                    'payment' => $order->payment,
                    'amount'  => $order->amount,
                    'other'   => $order->other,
                ]))->onQueue('test'));
            }
            DB::commit();
            return true;
        } catch (\Throwable $throwable) {
            DB::rollBack();
            Log::info($throwable->getMessage());
            return false;
        }
    }
}
